package model;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
import solver.moves.*;

import command.Invoker;

import util.ObjectIdPropertyPair;

public class MachineSelector {
	ArrayList<ObjectIdPropertyPair> m_a;
	int calls = 0;
	int maxcalls = 10;
	SolverEnvironment env;
		
	public MachineSelector(SolverEnvironment env) {
		this.env = env;
		m_a = new ArrayList<ObjectIdPropertyPair>(env.getProblem().M);
		setCurrentSolution(env.getCurrentSolution());
	}
	
	public void setCurrentSolution(Solution currentSolution){
		updateStructure();
	}
	
	public int selectMostLoadedMachine(int numOfMachines){
		int ret=0;
		try{
			ret = env.getRandom().nextInt(Math.min(numOfMachines, env.getProblem().M));
		}catch(Exception x){
			System.out.println(x);
		}
		
		if(calls==0)
			updateStructure();
		if(++calls==maxcalls){
			calls=0;			
		}
		
		synchronized (m_a) {
			return m_a.get(ret).getObjectId();
		}	
	}
	
	public int getMostLoadedMachine(int pos){	
		synchronized (m_a) {
			return m_a.get(pos).getObjectId();
		}	
	}
	
	public int selectLeastLoadedMachine(int numOfMachines){
		int ret = m_a.get(env.getProblem().M-1-env.getRandom().nextInt(Math.min(numOfMachines, env.getProblem().M))).getObjectId();
		if(calls==0)
			updateStructure();
		if(++calls==maxcalls){
			calls=0;			
		}
		return ret;
	}
				
	public void updateStructure(){
		if (env.getCurrentSolution().getCostComponents()!=null  && env.getCurrentSolution().getCostComponents()[1]>env.getCurrentSolution().getCostComponents()[0]){
			updateStructureWithBalance();
			return;
		}
//		new Thread(){
//			public void run(){			
//				synchronized (current_solution) {
				env.getCurrentSolution().refreshLoadCostContribution();
				env.getCurrentSolution().refreshBalanceCostContribution();
//				}
//				synchronized (m_a) {
					m_a.clear();
					for (int i = 0; i < env.getProblem().M; i++) {
						m_a.add(i,new ObjectIdPropertyPair(i, 
								env.getCurrentSolution().balance_cost_contribution_zipped[i]
							    + env.getCurrentSolution().load_cost_contribution_zipped[i]));
					}
					Collections.sort(m_a);
//					System.out.println(m_a);
//				}
//			}
//		}.start();
	}
	
	
	public void updateStructureWithLoad(){
		//new Thread(){
		//	public void run(){			
		//		synchronized (current_solution) {
		env.getCurrentSolution().refreshLoadCostContribution();
		//		}
		//		synchronized (m_a) {
		m_a.clear();
		for (int i = 0; i < env.getProblem().M; i++) {
			m_a.add(i,new ObjectIdPropertyPair(i, 
					env.getCurrentSolution().load_cost_contribution_zipped[i]));
		}
		Collections.sort(m_a);
		//			System.out.println(m_a);
		//		}
		//	}
		//}.start();
	}
	
	
	public void updateStructureWithBalance(){
		//new Thread(){
		//	public void run(){			
		//		synchronized (current_solution) {
		env.getCurrentSolution().refreshBalanceCostContribution();
		//		}
		//		synchronized (m_a) {
		m_a.clear();
		for (int i = 0; i < env.getProblem().M; i++) {
			m_a.add(i,new ObjectIdPropertyPair(i, 
					env.getCurrentSolution().balance_cost_contribution_zipped[i]));
		}
		Collections.sort(m_a);
		//			System.out.println(m_a);
		//		}
		//	}
		//}.start();
	}

	public List<Integer> getMachineIds() {
		if(calls==0)
			updateStructure();
		if(++calls==maxcalls){
			calls=0;			
		}
		List<Integer> ret = new ArrayList<Integer>();
		for(ObjectIdPropertyPair m:m_a)
			ret.add(m.getObjectId());
		return ret;
	}
}
